package com.strawcom.charmring.view;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import com.strawcom.charmring.App;
import com.strawcom.charmring.R;

/**
 * used to show results after exercise
 * 
 * @author WangPeng
 */
public class WaterCupView extends View {

	private int mWidth;
	private int mHeight;

	private final int MAX_COUNT = 6;
	private Bitmap bmpBubble;
	private Typeface tfWenZi  , tfShuZi;
	private final PorterDuffXfermode porterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP);
	private final Rect r = new Rect();
	private final RectF rf = new RectF();
	private final Paint mPaint = new Paint();
	private final Path mPath = new Path();

	private final int lightPercent = 65;
	private final int bessel = 9; // to control the water shock
	private int waterOffset = 0; // flow
	private int ringShadowWidth;
	private int textShadowWidth;
	private int ringWidth;
	private int waterMoveSpeed;
	private int shockHeight;
	private int titleTextSize;
	private int percentTextSize;
	private int infoTextSize;
	private int unitTextSize;
	private int bmpBubbleBoderWidth;
	
	private float waterTop , waterBottom;
	private float centerX, centerY;

	private int[] waterPercent; // value (0 ~ 100)
	private String[] waterValue;
	private String[] waterTitle, waterUnit;
	private boolean which; // false -> energy; true -> time
	private long whichTime;

	private boolean isFlowing = true;

	private final Random random = new Random();

	private final List<Bubble> bubbleList = new LinkedList<Bubble>();
	private final List<Bubble> deathList = new ArrayList<Bubble>();

	private final List<ColorMatrixColorFilter> colorMatrixColorFilterList = new ArrayList<ColorMatrixColorFilter>();

	private final ColorMatrix colorMatrixBlue = new ColorMatrix(new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, });
	private final ColorMatrix colorMatrixRed = new ColorMatrix(new float[] { 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, });
	private final ColorMatrix colorMatrixYellow = new ColorMatrix(
			new float[] { 5, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, });
	private final ColorMatrix colorMatrixGreen = new ColorMatrix(
			new float[] { 1, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, });
	private final ColorMatrix colorMatrixNormal = new ColorMatrix(
			new float[] { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, });

	public WaterCupView(Context context) {
		this(context, null);
	}

	public WaterCupView(Context context, AttributeSet attrs) {
		super(context, attrs);

		setLayerType(LAYER_TYPE_SOFTWARE, null);

		tfWenZi = App.i().tfYouYuan;
		tfShuZi = App.i().tfGeometr212;

		colorMatrixColorFilterList.add(new ColorMatrixColorFilter(colorMatrixBlue));
		colorMatrixColorFilterList.add(new ColorMatrixColorFilter(colorMatrixRed));
		colorMatrixColorFilterList.add(new ColorMatrixColorFilter(colorMatrixGreen));
		colorMatrixColorFilterList.add(new ColorMatrixColorFilter(colorMatrixYellow));
		colorMatrixColorFilterList.add(new ColorMatrixColorFilter(colorMatrixNormal));

		waterTitle = context.getResources().getStringArray(R.array.exercise_summary_type);
		waterUnit = context.getResources().getStringArray(R.array.exercise_summary_daily_unit);

		setValueInfo(new int[] { 0, 0 }, new float[] { 0, 0 });
		startRunWaterAnim();
	}

	@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		super.onSizeChanged(w, h, oldw, oldh);
		mWidth = w;
		mHeight = h;

		textShadowWidth = (int) 2;
		ringShadowWidth = (int) (mWidth * 0.02f);
		ringWidth = (int) (mWidth * 0.055f * 0.5f);
		shockHeight = (int) (mWidth * 0.04f);
		waterMoveSpeed = (int) (mWidth * 0.02f * 0.25f);

		titleTextSize = (int) (mWidth * 0.08f);
		percentTextSize = (int) (mWidth * 0.06f);
		infoTextSize = (int) (mWidth * 0.24f);
		unitTextSize = (int) (mWidth * 0.05f);

		// to prepare bubble resource
		
		bmpBubbleBoderWidth = 3;
		bmpBubble = Bitmap.createBitmap((int) (mWidth * 0.12f), (int) (mWidth * 0.12f), Config.ARGB_8888);
		Canvas canvas = new Canvas(bmpBubble);
//		// 实心红色气泡
//		mPaint.setAntiAlias(true);
//		mPaint.setStyle(Style.FILL);
//		mPaint.setColor(0xffd20264); 
//		canvas.drawCircle(bmpBubble.getWidth() * 0.5f, bmpBubble.getHeight() * 0.5f, 
//				bmpBubble.getWidth() * 0.5f, mPaint);
		// 彩色气泡
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Style.STROKE);
		mPaint.setColor(0xffdedede);
		mPaint.setStrokeWidth(bmpBubbleBoderWidth);
		canvas.drawCircle(bmpBubble.getWidth() * 0.5f, bmpBubble.getHeight() * 0.5f, (bmpBubble.getWidth() - bmpBubbleBoderWidth) * 0.5f,
				mPaint);
		mPaint.setStyle(Style.FILL);
		mPaint.setShader(new LinearGradient(0, bmpBubble.getHeight(), bmpBubble.getWidth(), 0, new int[] { 0x99ffffff, 0x02ffffff,
				0x00000000 }, new float[] { 0f, 0.85f, 1f }, Shader.TileMode.REPEAT));
		canvas.drawCircle(bmpBubble.getWidth() * 0.5f, bmpBubble.getHeight() * 0.5f, bmpBubble.getWidth() * 0.5f - bmpBubbleBoderWidth * 2,
				mPaint);
		mPaint.setStyle(Style.FILL);
		mPaint.setShader(new LinearGradient(bmpBubble.getWidth() * 0.225f, bmpBubble.getHeight() * 0.825f, bmpBubble.getWidth() * 0.525f,
				bmpBubble.getHeight() * 0.525f, new int[] { 0x99ffffff, 0x02ffffff }, new float[] { 0f, 0.5f }, Shader.TileMode.REPEAT));
		canvas.drawCircle(bmpBubble.getWidth() * 0.375f, bmpBubble.getHeight() * 0.675f, bmpBubble.getWidth() * 0.15f, mPaint);

		r.left = 0;
		r.top = 0;
		r.right = bmpBubble.getWidth();
		r.bottom = bmpBubble.getHeight();
		
		waterTop =  ringWidth + ringShadowWidth;
		waterBottom = mHeight - (ringWidth + ringShadowWidth);
		centerX = mWidth * 0.5f;
		centerY = mHeight * 0.5f;
	}

	@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, widthMeasureSpec);
	}

	/**
	 * [0] -> time ; [1] -> energy
	 * @param waterPercent [length 2] 
	 * @param waterValue [length 2]
	 */
	public void setValueInfo(int[] waterPercent, float[] waterValue) {
		this.waterPercent = waterPercent;
		this.waterValue = new String[] { String.format("%.1f", waterValue[0]), String.format("%.1f", waterValue[1]) };
		
		invalidate();
	}

	public void startRunWaterAnim() {
		isFlowing = true;
		invalidate();
	}

	public void stopRunWaterAnim() {
		isFlowing = false;
	}

	@Override protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		// draw background
		mPaint.reset();
		mPaint.setStyle(Style.FILL);
		mPaint.setColor(0xffe5e4e2);
		canvas.drawCircle(centerX, centerY, mWidth * 0.5f - (ringWidth + ringShadowWidth), mPaint);
		// draw water
		mPaint.setAntiAlias(true);
		mPaint.setColor(0xffff0461);
		mPaint.setXfermode(porterDuffXfermode);
		mPath.reset();

		int waterHeight = (int) (waterBottom - (waterBottom - waterTop) * (getWaterPercent() * 0.01f));
		mPath.moveTo(0, mHeight);
		mPath.lineTo(0 - waterOffset, waterHeight);
		int waterShock = mWidth / bessel;
		for (int i = 1; i <= bessel + 2; i++) {
			int mShock = shockHeight * (i % 2 == 0 ? 1 : -1);
			mPath.quadTo(waterShock * (i - 0.5f) - waterOffset, waterHeight + mShock, waterShock * i - waterOffset, waterHeight);
		}
		mPath.lineTo(mWidth, mHeight);
		mPath.close();
		canvas.drawPath(mPath, mPaint);
		// draw bubble
		mPaint.setAntiAlias(true);
		mPaint.setXfermode(porterDuffXfermode);
		drawBubble(canvas);
		mPaint.setXfermode(null);
		// draw circle ring
		
		// 1... draw circle shadow~
		mPaint.setColor(0xffffffff);
		mPaint.setStyle(Style.STROKE);
		mPaint.setStrokeWidth(ringShadowWidth / 2);
		mPaint.setShadowLayer(ringShadowWidth, 0, 0, 0xff000000);
		
		canvas.drawCircle(mWidth * 0.5f, mHeight * 0.5f,  mWidth * 0.5f - (ringWidth + 1.5f * ringShadowWidth), mPaint);
		// 2...
//		mPaint.setColor(System.currentTimeMillis() - whichTime > 50 ? 0xffffffff : 0xff00ffff);
		mPaint.setColor( 0xffffffff); // 取消高亮
		mPaint.setStyle(Style.STROKE);
		mPaint.setStrokeWidth(ringWidth);
		mPaint.clearShadowLayer();
		canvas.drawCircle(mWidth * 0.5f, mHeight * 0.5f, mWidth * 0.5f - (ringWidth + ringShadowWidth), mPaint);
		
		
		// draw text
		mPaint.reset();
		mPaint.setAntiAlias(true);
		mPaint.setStyle(Style.FILL);
		mPaint.setTypeface(tfWenZi);
		mPaint.setTextSize(titleTextSize);
		mPaint.setColor(getWaterPercent() < lightPercent ? 0xff848484 : 0xffffffff);
//		mPaint.setShadowLayer(textShadowWidth, 10, 10, getWaterPercent() < lightPercent ? 0xffaaaaaa : 0xff666666);
		canvas.drawText(getWaterTitle(), (mWidth - calcTextOffset(getWaterTitle(), mPaint)) * 0.5f, mHeight * 0.30f, mPaint);
		mPaint.setTypeface(tfShuZi);
		mPaint.setTextSize(percentTextSize);
		canvas.drawText(getWaterPercentText(), (mWidth - calcTextOffset(getWaterPercent() + "%", mPaint)) * 0.5f, mHeight * 0.38f, mPaint);
		mPaint.setTextSize(infoTextSize);
		
//		mPaint.setColor(getWaterPercent() < lightPercent - 20 ? 0xff848484 : 0xffffffff);
		mPaint.setColor(0xffffffff);
		mPaint.setShadowLayer(textShadowWidth, 5, 5, 0xff666666);
		canvas.drawText(getWaterValue(), (mWidth - calcTextOffset(getWaterValue(), mPaint)) * 0.5f, mHeight * 0.74f, mPaint);
		mPaint.setTypeface(tfWenZi);
		mPaint.setTextSize(unitTextSize);
		canvas.drawText(getWaterUnit(), (mWidth - calcTextOffset(getWaterUnit(), mPaint)) * 0.5f, mHeight * 0.86f, mPaint);

		// flowing
		waterOffset += waterMoveSpeed;
		if (waterOffset * 0.5f > mWidth / bessel) {
			waterOffset = 0;
		}
		if (isFlowing) {
			invalidate();
		}
	}

	private float calcTextOffset(String text, Paint paint) {
		float[] textWidths = new float[text.length()];
		paint.getTextWidths(text, textWidths);
		float textTotalWidth = 0;
		for (float f : textWidths) {
			textTotalWidth += f;
		}
		return textTotalWidth;
	}

	private class Bubble {
		int current; // record self location
		float location;
		int risingSpeed;
		float scaleSize;
		ColorMatrixColorFilter colorMatrixColorFilter;
		long lifeTime;

		private boolean isDeath() {
			return System.currentTimeMillis() > lifeTime;
		}
	}

	private Bubble nextBubble() {
		Bubble bubble = new Bubble();
		bubble.location = 0.1f + random.nextFloat() * 0.6f;
		bubble.risingSpeed = 3 + (int) (random.nextFloat() * 12);
		bubble.scaleSize = 0.5f + random.nextFloat() * 0.7f;
		bubble.colorMatrixColorFilter = colorMatrixColorFilterList.get(random.nextInt(colorMatrixColorFilterList.size()));
		bubble.lifeTime = System.currentTimeMillis() + (long) ((5 + random.nextFloat() * 4) * 1000);
		return bubble;
	}

	private void drawBubble(Canvas canvas) {
		deathList.clear();
		for (Bubble bubble : bubbleList) {
			if (bubble.isDeath()) {
				deathList.add(bubble);
			} else {
				mPaint.setColorFilter(bubble.colorMatrixColorFilter);
				bubble.current = bubble.current - bubble.risingSpeed;

				rf.left = (int) (mWidth * bubble.location);
				rf.right = rf.left + (int) (bmpBubble.getWidth() * bubble.scaleSize);
				rf.top = bubble.current + mHeight;
				rf.bottom = rf.top + (int) (bmpBubble.getHeight() * bubble.scaleSize);
				canvas.drawBitmap(bmpBubble, r, rf, mPaint);
			}
		}

		bubbleList.removeAll(deathList);

		if (bubbleList.size() < MAX_COUNT) {
			bubbleList.add(nextBubble());
		}
	}

	@Override public boolean onTouchEvent(MotionEvent event) {
		if (event.getAction() == MotionEvent.ACTION_UP) {
			which = !which;
			whichTime = System.currentTimeMillis();
			invalidate();
		}
		return true;
	}

	private int getWaterPercent() {
		int percent = waterPercent[which ? 0 : 1];
		if(percent < 0) {
			percent = 0;
		}
		else if(percent > 100) {
			percent = 100;
		}
		return percent;
	}
	
	private String getWaterPercentText() {
		return waterPercent[which ? 0 : 1] + "%";
	}

	private String getWaterValue() {
		return waterValue[which ? 0 : 1];
	}

	private String getWaterTitle() {
		return waterTitle[which ? 0 : 1];
	}

	private String getWaterUnit() {
		return waterUnit[which ? 0 : 1];
	}
}